#include "test.h"
#include <sys/ioctl.h>
#include <linux/fb.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <pthread.h>


//read/write文件IO，适用于顺序访问文件、网络 I/O、实时数据流和文件分块传输的场景。例如网络服务、流式文件写入、日志管理等。
int io_test() {
    int fd;
    char *filename = "rw_example.txt";
    char write_buf[] = "Hello, Linux file I/O!";
    char read_buf[100] = {0};

    ENABLE_FILE_LOG("log_io_test.txt"); //日志写入到文件

    // 打开文件，如果不存在则创建
    fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, 0644);
    if (fd < 0) {
        LOG_ERROR("Failed to open file\n");
        return 1;
    }

    LOG_INFO("File descriptor: %d\n", fd);
    LOG_INFO("Write buffer size: %lu\n", sizeof(write_buf));

    // 清空文件内容
    if (ftruncate(fd, 0) == -1) {
        LOG_ERROR("Failed to truncate file");
        close(fd);
        return 1;
    }

    // 写入文件
    ssize_t bytes_written = write(fd, write_buf, sizeof(write_buf));
    if (bytes_written < 0) {
        LOG_ERROR("Failed to write to file\n");
        close(fd);
        return 1;
    }

    LOG_INFO("Bytes written: %ld\n", bytes_written);
    LOG_INFO("File pointer after write: %ld\n", lseek(fd, 0, SEEK_CUR));

    // 移动文件指针到文件开头，验证顺序访问
    lseek(fd, 0, SEEK_SET);
    LOG_INFO("File pointer reset to start: %ld\n", lseek(fd, 0, SEEK_CUR));

    // 读取文件内容
    ssize_t bytes_read = read(fd, read_buf, sizeof(write_buf));
    if (bytes_read < 0) {
        LOG_ERROR("Failed to read from file\n");
        close(fd);
        return 1;
    }

    LOG_INFO("Bytes read: %ld\n", bytes_read);
    LOG_INFO("Read from file: %s\n", read_buf);
    LOG_INFO("File pointer after read: %ld\n", lseek(fd, 0, SEEK_CUR));

    // 关闭文件
    close(fd);
    //关闭日志输出到文件
    DISABLE_FILE_LOG();
    return 0;
}



//mmap文件映射, 适用于需要频繁读写、随机访问、处理大文件的场景。例如数据库存储管理、图像处理、文件缓存等
int mmap_test() {
    
    const char *filename = "mmap_example.txt";

    ENABLE_FILE_LOG("log_mmap_test.txt" );//日志写入到文件

    int fd = open(filename, O_RDWR | O_CREAT, 664);
    if (fd == -1) {
        LOG_ERROR("Failed to open file");
        return 1;
    }
    // 清空文件内容
    if (ftruncate(fd, 0) == -1) {
        LOG_ERROR("Failed to truncate file");
        close(fd);
        return 1;
    }
    // 设置文件大小为 100 字节，确保 mmap 访问不越界
    size_t filesize = 100;
    if (ftruncate(fd, filesize) == -1) {
        LOG_ERROR("Failed to set file size");
        close(fd);
        return 1;
    }
    // 获取并验证文件大小
    size_t verify_size = lseek(fd, 0, SEEK_END);
    if(verify_size != filesize)
    {
        LOG_ERROR("Failed to verify file size");
        close(fd);
        return 1;        
    }
    LOG_INFO("verify filesize:%d\r\n",verify_size);

    // 将文件映射到内存
    char *map = mmap(NULL, filesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (map == MAP_FAILED) {
        LOG_ERROR("Failed to mmap file");
        close(fd);
        return 1;
    }
    LOG_INFO("*map:%d\r\n",map);
    close(fd);  // 文件已映射到内存，关闭文件描述符

    // 读取第 20 到第 22 字节内容
    char buffer[4] = {0};  // 为方便打印，这里多留一个字节用于存放 '\0'
    memcpy(buffer, map + 20, 3);
    LOG_INFO("Data from position 20 to 22 before modification: %s\n", buffer);
    
    // 写入新内容 "ABC" 到第 20 到第 22 字节
    memcpy(map + 20, "ABC", 3);

    // 验证写入后的内容
    memset(buffer, 0, sizeof(buffer));  // 清空 buffer 以重新读取
    memcpy(buffer, map + 20, 3);
    LOG_INFO("Data from position 20 to 22 after modification: %s\n", buffer);

    // 解除映射
    if (munmap(map, filesize) == -1) {
        LOG_ERROR("Failed to munmap file");
        return 1;
    }
    //关闭日志输出到文件
    DISABLE_FILE_LOG();
    return 0;
}



int fb_test() {
    int fb_fd = open("/dev/fb0", O_RDWR);
    if (fb_fd == -1) {
        LOG_ERROR("无法打开帧缓冲设备");
        return -1;
    }
    LOG_DEBUG("/dev/fb0 fb_fd: %ld\n", fb_fd);
    struct fb_var_screeninfo vinfo;
    struct fb_fix_screeninfo finfo;

    // 获取帧缓冲的固定信息
    if (ioctl(fb_fd, FBIOGET_FSCREENINFO, &finfo)) {
        LOG_ERROR("无法读取固定屏幕信息");
        close(fb_fd);
        return -1;
    }

    // 获取帧缓冲的可变信息
    if (ioctl(fb_fd, FBIOGET_VSCREENINFO, &vinfo)) {
        LOG_ERROR("无法读取可变屏幕信息");
        close(fb_fd);
        return -1;
    }

    // 计算屏幕大小（字节数）
    int screensize = vinfo.yres_virtual * finfo.line_length;
    LOG_DEBUG("screensize: [%ld, %ld]\n", vinfo.yres_virtual, finfo.line_length);
    
    // 将帧缓冲区映射到内存
    char *fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fb_fd, 0);
    if ((int)fbp == -1) {
        LOG_ERROR("无法映射帧缓冲区到内存");
        close(fb_fd);
        return -1;
    }

    // 设置颜色（16位RGB565模式：0xF800 表示红色）
    int x, y;
    unsigned int color = 0xF800; // 红色
    for (y = 0; y < vinfo.yres; y++) {
        for (x = 0; x < vinfo.xres; x++) {
            long location = (x + vinfo.xoffset) * (vinfo.bits_per_pixel / 8) +
                            (y + vinfo.yoffset) * finfo.line_length;

            *((unsigned short int *)(fbp + location)) = color;
        }
    }

    // 等待一段时间，让颜色块显示出来
    sleep(5);

    // 取消映射并关闭文件
    munmap(fbp, screensize);
    close(fb_fd);

    return 0;
}

int global_var = 100; // 全局变量，用于测试变量独立性

void progress_handle_client(int client_id) {
    int local_var = 200; // 局部变量，用于测试变量独立性
    int *dynamic_mem = malloc(sizeof(int)); // 动态分配内存
    *dynamic_mem = 300;

    // 打开文件，父子进程会得到独立的文件描述符
    int fd = open("test_file.txt", O_RDWR | O_CREAT | O_APPEND, 0666);
    if (fd < 0) {
        LOG_ERROR("无法打开文件\n");
        exit(1);
    }

    // 修改变量和写入文件
    global_var += client_id;
    local_var += client_id;
    *dynamic_mem += client_id;
    dprintf(fd, "子进程 %d: 全局变量 = %d, 局部变量 = %d, 动态内存 = %d, 文件描述符 = %d\n",
            getpid(), global_var, local_var, *dynamic_mem, fd);
    // sleep(5);
    // 显示子进程修改后的变量值
    LOG_DEBUG("子进程 %d: 全局变量 = %d, 局部变量 = %d, 动态内存 = %d, 文件描述符 = %d, 文件描述符地址 = %d\n",
              getpid(), global_var, local_var, *dynamic_mem, fd, &fd);

    // 关闭文件和释放内存
    close(fd);
    free(dynamic_mem);
}


int progress_test() {
      int client_id = 1;

    // 在父进程中创建5个子进程
    while (client_id <= 5) {
        pid_t pid = fork();
        if (pid < 0) {
            LOG_ERROR("创建子进程失败\n");
            exit(1);
        } else if (pid == 0) {
            // 子进程中运行的代码
            progress_handle_client(client_id);
            exit(0); // 子进程退出
        }

        // 父进程继续创建下一个子进程
        client_id++;
    }

    // 父进程等待所有子进程完成
    while (wait(NULL) > 0);

    // 父进程中的变量值
    LOG_DEBUG("父进程: 全局变量 = %d\n", global_var);
    return 0;
}


int pthread_global_var = 100; // 全局变量，多个线程共享

void *pthread_handle_client(void *arg) {
    int client_id = *((int *)arg);
    int local_var = 200; // 局部变量，独立于每个线程
    int *dynamic_mem = malloc(sizeof(int)); // 动态内存分配，独立于每个线程
    *dynamic_mem = 300;

    // 模拟资源共享和逻辑独立
    pthread_global_var += client_id;
    local_var += client_id;
    *dynamic_mem += client_id;

    LOG_INFO("线程 %ld: 全局变量 = %d, 局部变量 = %d, 动态内存 = %d\n",
             pthread_self(), pthread_global_var, local_var, *dynamic_mem);

    sleep(rand() % 3); // 随机睡眠，模拟处理时间差异

    LOG_INFO("线程 %ld 完成客户端 %d 的请求\n", pthread_self(), client_id);


    free(dynamic_mem); // 释放动态内存
    return NULL;
}

int pthread_test() {
    pthread_t threads[5];
    int client_ids[5];

    for (int i = 0; i < 5; i++) { // 模拟 5 个客户端请求
        client_ids[i] = i + 1;
        int ret = pthread_create(&threads[i], NULL, pthread_handle_client, (void *)&client_ids[i]);
        if (ret != 0) {
            LOG_ERROR("创建线程失败");
            exit(1);
        }
    }

    // 等待所有线程完成
    for (int i = 0; i < 5; i++) {
        pthread_join(threads[i], NULL);
    }

    LOG_DEBUG("服务器处理完所有请求，退出。全局变量 = %d\n", pthread_global_var);
    return 0;
}

void msleep(int milliseconds) {
    struct timespec ts;
    ts.tv_sec = milliseconds / 1000;             // 秒
    ts.tv_nsec = (milliseconds % 1000) * 1000000; // 毫秒转换为纳秒

    // 调用 nanosleep 进行延时
    nanosleep(&ts, NULL);
}

int pthreads_counter = 0; // 全局变量，多个线程共享
pthread_mutex_t lock; // 互斥锁

void *increment_counter(void *arg) {
    for (int i = 0; i < 100000; i++) {
        pthread_mutex_lock(&lock); // 上锁
        pthreads_counter++; // 临界区
        pthread_mutex_unlock(&lock); // 解锁
    }
    return NULL;
}

int pthread_mutex_lock_test() {
    pthread_t threads[5];
    pthread_mutex_init(&lock, NULL); // 初始化互斥锁

    for (int i = 0; i < 5; i++) {
        pthread_create(&threads[i], NULL, increment_counter, NULL);
    }

    for (int i = 0; i < 5; i++) {
        pthread_join(threads[i], NULL);
    }

    LOG_INFO("最终计数器值：%d\n", pthreads_counter); // 期望输出 500000
    pthread_mutex_destroy(&lock); // 销毁互斥锁
    return 0;
}


void write_to_file() {
    int fd = open("shared_file.txt", O_RDWR | O_CREAT, 0666);
    if (fd < 0) {
        perror("无法打开文件");
        exit(1);
    }

    // 文件加锁
    struct flock lock;
    lock.l_type = F_WRLCK; // 写锁
    lock.l_whence = SEEK_SET;
    lock.l_start = 0;
    lock.l_len = 0;
    fcntl(fd, F_SETLKW, &lock);

    // 临界区：写文件
    dprintf(fd, "子进程 %d 正在写入文件。\n", getpid());
    LOG_INFO("子进程 %d 正在写入文件。\n", getpid());
    sleep(1); // 模拟写操作时间

    // 解锁
    lock.l_type = F_UNLCK;
    fcntl(fd, F_SETLKW, &lock);
    close(fd);
}

int progress_file_lock_test() {
    pid_t pid;

    for (int i = 0; i < 5; i++) {
        pid = fork();
        if (pid == 0) { // 子进程
            write_to_file();
            exit(0);
        }
    }

    // 等待所有子进程结束
    while (wait(NULL) > 0);
    LOG_INFO("所有子进程写入完成\n");

    return 0;
}


pthread_mutex_t mutex;

void *thread_func(void *arg) {
    while (1) {
        if (pthread_mutex_trylock(&mutex) == 0) {
            // 成功获取锁，执行临界区操作
            LOG_INFO("线程 %ld: 获取到锁，正在执行\n", pthread_self());
            // 执行临界区代码
            pthread_mutex_unlock(&mutex);  // 释放锁
        } else {
            // 获取锁失败，做其他事情或者继续尝试
            LOG_INFO("线程 %ld: 锁被占用，继续循环\n", pthread_self());
        }
        sleep(1);  // 模拟一些非临界区的工作
    }
    return NULL;
}

int Non_blocking_mutex_lock() {
    pthread_t threads[2];

    // 初始化互斥锁
    pthread_mutex_init(&mutex, NULL);

    // 创建线程
    for (int i = 0; i < 2; i++) {
        pthread_create(&threads[i], NULL, thread_func, NULL);
    }

    // 等待线程结束
    for (int i = 0; i < 2; i++) {
        pthread_join(threads[i], NULL);
    }

    // 销毁互斥锁
    pthread_mutex_destroy(&mutex);

    return 0;
}


//Interprocess naming semaphores  POSIX 进程间命名信号量

#define SEM_NAME "/my_semaphore"  // 命名信号量的名称

// 共享资源访问函数
void access_shared_resource(const char *process_name, sem_t *sem) {
    LOG_INFO("%s 尝试获取锁...\n", process_name);
    sem_wait(sem); // 获取信号量，锁定资源

    LOG_INFO("%s 获取到锁，正在访问共享资源...\n", process_name);
    sleep(2); // 模拟访问共享资源的时间
    LOG_INFO("%s 访问完成，释放锁...\n", process_name);

    sem_post(sem); // 释放信号量，解锁资源
}

int inter_pro_name_sem_test() {
    sem_t *sem;

    // 创建或打开一个命名信号量，初始值为1
    sem = sem_open(SEM_NAME, O_CREAT | O_EXCL, 0644, 1);
    if (sem == SEM_FAILED) {
        perror("创建信号量失败");
        exit(EXIT_FAILURE);
    }

    // 创建两个子进程
    pid_t pid1 = fork(); // 创建第一个子进程
    if (pid1 < 0) {
        perror("创建进程 1 失败");
        exit(EXIT_FAILURE);
    } else if (pid1 == 0) {
        // 子进程 1 调用资源访问函数
        access_shared_resource("进程 1", sem);
        exit(0);
    }

    pid_t pid2 = fork(); // 创建第二个子进程
    if (pid2 < 0) {
        perror("创建进程 2 失败");
        exit(EXIT_FAILURE);
    } else if (pid2 == 0) {
        // 子进程 2 调用资源访问函数
        access_shared_resource("进程 2", sem);
        exit(0);
    }

    // 等待所有子进程结束
    waitpid(pid1, NULL, 0);
    waitpid(pid2, NULL, 0);

    // 关闭并删除命名信号量
    sem_close(sem);
    sem_unlink(SEM_NAME);

    LOG_INFO("所有进程完成，退出。\n");
    return 0;
}

// 处理 SIGALRM 信号的函数
void alarm_handler(int signum) {
    LOG_INFO("收到 SIGALRM 信号！执行定时任务...\n");
}

int signal_test() {
    // 注册 SIGALRM 信号处理函数
    signal(SIGALRM, alarm_handler);

    // 设置一个 3 秒的定时器
    LOG_INFO("设置定时器，10 秒后触发 SIGALRM 信号...\n");
    alarm(10);

    // 无限循环，等待信号
    while (1) {
        pause(); // 暂停，等待信号触发
    }

    return 0;
}